package Derivation;

import java.util.List;
import java.util.Vector;
import java.util.concurrent.CopyOnWriteArrayList;

import Basics.*;

public class DeriveByRuleBottomUp extends DeriveByRule
{
	
	
	
	public DeriveByRuleBottomUp (Rule ir)
	{
		super(ir);
	}



	/*************************************************************************************************************/
	/** Title: FindDerivationsForRuleBottomUp																				
	/** Description: Finds all Derivations for the rule according to db 				
	/*************************************************************************************************************/
	
	public void FindDerivationsForRuleBottomUp () 
	{
		List<Rule> instRuleVector = new CopyOnWriteArrayList<Rule>();
		List<Rule> compareInstRuleVector = new CopyOnWriteArrayList<Rule>();
		instRuleVector.add(new Rule(this.r));
		
		while (false == compareInstRuleVector.equals(instRuleVector))
		{
			for (Rule rule : instRuleVector) //copy all vector info to comparison vector 
			{
				if (false == compareInstRuleVector.contains(rule)) 
				{
					compareInstRuleVector.add(rule);
				}
			}
			
			instRuleVector = InstIterationBottomUp(instRuleVector);
		}
		
		for (Rule rule : instRuleVector) 
		{
			if (true == rule.isFullyInst()) 
			{
				this.derivations.add(rule);
			}
		}
	}
	
	
	
	
	/*************************************************************************************************************/
	/** Title: InstIterationBottomUp																				
	/** Description: One iteration to update the instRuleVector in partly inst rules  				
	/*************************************************************************************************************/
	static int i = 0;
	public List<Rule> InstIterationBottomUp (List<Rule> instRuleVector)
	{
		for (Rule rule : instRuleVector)
		{
			Rule copyOfRule = new Rule (rule);
			for (Atom partlyInstAtom : copyOfRule.getBody()) 
			{
					//////////////////////////////////////////////////////
					i++;
					long startTime = System.currentTimeMillis();
					//////////////////////////////////////////////////////
				Vector<Atom> relevants = FindRelevantInstAtoms(partlyInstAtom);
				long endTime = System.currentTimeMillis();
				double durationFullProv = (endTime - startTime);
				System.out.println("itration num: " + i + " time for iteration: " + durationFullProv);
				for (Atom atom : relevants) 
				{
					Rule temp = new Rule (copyOfRule);
					temp.SwapToInstAtomAndPartiallyInst(partlyInstAtom, atom);					
					if (false == instRuleVector.contains(temp))
					{
						instRuleVector.add(temp);
					}
				}
			}
		}
		
		return instRuleVector;
	}
	
	
	
	
	/*************************************************************************************************************/
	/** Title: FindRelevantInstAtoms																				
	/** Description: Finds the relevant atoms for the current partial inst. in the rule 				
	/*************************************************************************************************************/
	
	public Vector<Atom> FindRelevantInstAtoms (Atom partlyInstAtom)
	{
		Vector<Atom> relevantAtoms = new Vector<Atom>();
		if (true == partlyInstAtom.isFullyInst()) 
		{
			relevantAtoms.add(partlyInstAtom);
		}
		
		else
		{
			relevantAtoms = DB.getInstance().GetRelevantFactsFromDB(partlyInstAtom);
		}
		
		return relevantAtoms;
	}
	
	
	
	
	/*************************************************************************************************************/
	/** Title: FittsPartialInst																				
	/** Description: Checks if instAtom from the DB fitts the current partial inst. atom 				
	/*************************************************************************************************************/
	
	/*public boolean FittsPartialInst (Atom partlyInstAtom, Atom instAtom)
	{
		boolean retVal = true;
		if (false == partlyInstAtom.getName().equals(instAtom.getName()))
		{
			retVal = false;
		}
		
		if (partlyInstAtom.getParams().size() != instAtom.getParams().size())
		{
			retVal = false;
		}
		
		for (Proton param : partlyInstAtom.getParams()) 
		{	
			if (param instanceof Constant)
			{
				if ( false == instAtom.getParams().contains(param) )
				{
					retVal = false;
					break;
				}
				
				int partlyInstIdx = partlyInstAtom.getParams().indexOf(param);
				int instIdx = instAtom.getParams().indexOf(param);
				if (partlyInstIdx != instIdx)
				{
					retVal = false;
				}
			}
		}
		
		return retVal;
	}	*/
}
